﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Planer.Model.Validators;
using Planer.Model.Validators.Base;
using Planer.UI;
using System.Windows.Forms;

namespace Planer.Model
{
    public class BillingModel
    {
        static BillingModel model = null;

        protected BillingModel()
        {
            
        }

        public static BillingModel GetInstance()
        {
            if (model == null)
            {
                model = new BillingModel();
            }

            return model;
        }

        public List<billing> GetBillingListByUser(user User)
        {
            List<billing> billingList = new List<billing>();
            //period p = PeriodModel.GetInstance().GetCurrentPeriod();

            var query = from bl in Program.Db.billings//.Include("actions").Include("actions.action_category")
                        where bl.user.id == User.id //|| bl.actions.Any(act => act.period.id == p.id)                        
                        orderby bl.create_date                        
                        select bl;
           
            billingList.AddRange(query.ToList<billing>());

            //string q = Program.Db.billings.ToTraceString();

            return billingList;
        }

        public ModelResult SaveOrUpdateBilling(billing Bill)
        {
            if (Bill == null) throw new ArgumentNullException("Bill", "Пустой объект счета");
            BillingValidator validator = new BillingValidator();

            validator.Validate(Bill);
            if (validator.Status == OperationStatusType.ERROR)
            {
                return new ModelResult(validator.Errors);
            }

            if (Bill.id == 0)
            {
                Program.Db.AddTobillings(Bill);
            }

            if (Program.Db.SaveChanges() > 0)
            {
                return new ModelResult();
            }
            else
            {
                return new ModelResult("Ошибка сохранения данных");
            }
        }

        public ModelResult TransferMoney(billing From, billing To, float Money)
        {
            action_category transfer = ActionCategoryModel.GetInstance().GetTransferActionCategory();
            period per = PeriodModel.GetInstance().GetCurrentPeriod();

            action actFrom = new action()
            {
                action_category = transfer,
                amount = -Money,
                billing = From,
                create_date = DateTime.Now,
                descr = ActionCategoryModel.TRANSFER_ACTION_CATEGORY_NAME,
                period = per
            };

            ModelResult mr = MoneyOperation(From, actFrom);
            if (mr.Status == OperationStatusType.ERROR)
            {
                return mr;
            }

            action actTo = new action()
            {
                action_category = transfer,
                amount = Money,
                billing = To,
                create_date = DateTime.Now,
                descr = ActionCategoryModel.TRANSFER_ACTION_CATEGORY_NAME,
                period = per
            };

            mr = MoneyOperation(To, actTo);
            if (mr.Status == OperationStatusType.ERROR)
            {
                return mr;
            } 

            return new ModelResult();
        }

        public ModelResult MoneyOperation(billing Bill, action action)
        {
            if (action.amount == 0) return new ModelResult("Попытка перевода нулевой суммы");
            if (action.amount < 0 && Math.Abs(action.amount) > Bill.balance)
            {
                return new ModelResult("На счету недостаточно средств для перевода требуемой суммы");
            }
            ActionModel.GetInstance().AddAction(action);
            Bill.balance += action.amount;
            return SaveOrUpdateBilling(Bill);
        }

        public ModelResult MoneyOperation(billing Bill, periodical_action_transanction trans)
        {
            if (trans.periodical_action.amount == 0) return new ModelResult("Попытка перевода нулевой суммы");
            if (trans.periodical_action.amount < 0 && Math.Abs(trans.periodical_action.amount) > Bill.balance)
            {
                return new ModelResult("На счету недостаточно средств для перевода требуемой суммы");
            }

            PeriodicalActionTransactionModel.GetInstance().SaveOrUpdatePeriodicalActionTransaction(trans);
            Bill.balance += trans.periodical_action.amount;
            return SaveOrUpdateBilling(Bill);
        }

        public ModelResult MoneyOperation(billing Bill, allocation_transanction trans)
        {
            if (trans.allocation.amount == 0) return new ModelResult("Попытка перевода нулевой суммы");
            if (trans.allocation.amount > Bill.balance)
            {
                return new ModelResult("На счету недостаточно средств для перевода требуемой суммы");
            }

            AllocationTransactionModel.GetInstance().SaveOrUpdatePeriodicalAllocationTransaction(trans);
            if (trans.allocation.financial_goal != null)
            {
                trans.allocation.financial_goal.balance += trans.allocation.amount;
            }
            else if (trans.allocation.accumulation != null)
            {
                trans.allocation.accumulation.balance += trans.allocation.amount;
            }
            else
            {
                return new ModelResult("Пустые направления отчисления");
            }
            Bill.balance -= trans.allocation.amount;
            return SaveOrUpdateBilling(Bill);
        }
    }
}
